package com.wrt.sps.mgt.service.impl;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.wrt.sps.mgt.dao.WritingDao;
import com.wrt.sps.mgt.entity.UploadFile;
import com.wrt.sps.mgt.entity.Writing;
import com.wrt.sps.mgt.event.UploadFileEvent;
import com.wrt.sps.mgt.pojo.WritingDTO;
import com.wrt.sps.mgt.pojo.WritingQueryDTO;
import com.wrt.sps.mgt.service.WritingService;

/**
 * 文章管理服务实现层
 * 
 * @author 文瑞涛
 * @date 2020年12月19日 下午5:12:48
 */
@Service
public class WritingServiceImpl implements WritingService {

	@Autowired
	private ApplicationEventPublisher publisher;

	@Resource
	private WritingDao writingDao;

	@Override
	@Transactional(readOnly = true)
	public Page<Writing> query(WritingQueryDTO dto, int page, int limit) {
		Pageable pageable = PageRequest.of(page, limit, Sort.by(Sort.Direction.DESC, "createdDate", "id"));
		return writingDao.findAll(queryPageSpecification(dto), pageable);
	}

	/**
	 * 
	 * 分页查询条件生成
	 * 
	 * @param 文章查询实体 dto
	 * 
	 * @return 查询明细
	 */
	private Specification<Writing> queryPageSpecification(WritingQueryDTO dto) {
		return new Specification<Writing>() {
			/**
			 * 
			 */
			private static final long serialVersionUID = 8213213937970279605L;

			@Override
			public Predicate toPredicate(Root<Writing> root, CriteriaQuery<?> criteriaQuery,
					CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicates = new ArrayList<>(); // 所有的断言
				if (StringUtils.isNotBlank(dto.getTitle())) {
					predicates.add(criteriaBuilder.like(root.get("title"), "%" + dto.getTitle() + "%"));
				}
				if (null != dto.getStarttime() && null != dto.getEndtime()
						&& dto.getStarttime().before(dto.getEndtime())) {
					predicates.add(
							criteriaBuilder.between(root.get("createdDate"), dto.getStarttime(), dto.getEndtime()));
				}
				if (null != dto.getValidFlag()) {
					predicates.add(dto.getValidFlag().booleanValue() ? criteriaBuilder.isTrue(root.get("validFlag"))
							: criteriaBuilder.isFalse(root.get("validFlag")));
				}
				predicates.add(criteriaBuilder.equal(root.get("type"), dto.getType()));
				return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
			}
		};
	}

	@Override
	@Transactional(readOnly = true)
	public List<Long> countWritings() {
		List<Long> result = new ArrayList<>();
		result.add(writingDao.count());
		result.add(writingDao.countByValidFlag(true));
		result.add(writingDao.countByValidFlag(false));
		return result;
	}

	@Override
	@Transactional(readOnly = true)
	public Map<Writing.Type, Long> countWritingsByType() {
		Writing.Type[] types = Writing.Type.values();
		EnumMap<Writing.Type, Long> result = new EnumMap<>(Writing.Type.class);
		for (Writing.Type type : types) {
			result.put(type, writingDao.countByType(type));
		}
		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Writing save(WritingDTO dto) {
		Writing saveWriting = null;
		if (null != dto.getKey() && 0 != dto.getKey()) {
			Optional<Writing> temp = writingDao.findById(dto.getKey());
			if (temp.isPresent()) {
				saveWriting = temp.get();
			} else {
				return null;
			}
		} else {
			saveWriting = new Writing();
			saveWriting.setValidFlag(true);
		}
		saveWriting.setTitle(dto.getTitle());
		saveWriting.setComments(dto.getComments());
		if (StringUtils.isNotBlank(saveWriting.getImgUrl())
				&& !saveWriting.getImgUrl().equalsIgnoreCase(dto.getImgUrl())) {
			publisher.publishEvent(
					new UploadFileEvent(this, new UploadFile(WritingDTO.getImgCode(saveWriting.getImgUrl()), false)));
		}
		if (StringUtils.isBlank(dto.getImgUrl())) {
			saveWriting.setImgUrl(null);
		} else {
			saveWriting.setImgUrl(dto.getImgUrl());
		}
		saveWriting.setDetails(dto.getDetails());
		saveWriting.setType(dto.getType());
		return writingDao.save(saveWriting);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delete(Long id) {
		Optional<Writing> temp = writingDao.findById(id);
		if (temp.isPresent() && !temp.get().getValidFlag().booleanValue()) {
			publisher.publishEvent(
					new UploadFileEvent(this, new UploadFile(WritingDTO.getImgCode(temp.get().getImgUrl()), false)));
			List<String> imgCodeInDetails = WritingDTO.getImgCodesInDetails(temp.get().getDetails());
			if (!imgCodeInDetails.isEmpty()) {
				for (String imgcode : imgCodeInDetails) {
					publisher.publishEvent(new UploadFileEvent(this, new UploadFile(imgcode, false)));
				}
			}
			writingDao.deleteById(id);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Writing display(Long id, boolean isShow) {
		Optional<Writing> temp = writingDao.findById(id);
		if (temp.isPresent()) {
			Writing saveWriting = temp.get();
			saveWriting.setValidFlag(isShow);
			return writingDao.save(saveWriting);
		} else {
			return null;
		}
	}

	@Override
	@Transactional(readOnly = true)
	public Writing findById(Long id) {
		Optional<Writing> temp = writingDao.findById(id);
		if (temp.isPresent()) {
			return temp.get();
		} else {
			return null;
		}
	}

}
